/*
     Copyright 2007 Joseph M. Ferner

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Runtime.InteropServices;
using OpenServers.Net.Common.User;

namespace OpenServers.Net.Common.Security {
    /// <summary>
    /// Security provider that authenticates the user against windows user auth system.
    /// </summary>
    public class NtAuthSecurityProvider : AbstractSecurityProvider {
        // Declare the logon types as constants
        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_LOGON_NETWORK = 3;

        // Declare the logon providers as constants
        private const int LOGON32_PROVIDER_DEFAULT = 0;
        private const int LOGON32_PROVIDER_WINNT50 = 3;
        private const int LOGON32_PROVIDER_WINNT40 = 2;
        private const int LOGON32_PROVIDER_WINNT35 = 1;

        //Import Needed DLL
        [DllImport("advapi32.dll", EntryPoint = "LogonUser", SetLastError = true)]
        private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        /// <summary>
        /// validates a user in the system.
        /// </summary>
        public override IUser ValidateUser(string userNameAndDomain, string password) {
            string userName;
            string domain;
            SplitIntoUserNameAndDomain(userNameAndDomain, out userName, out domain);

            IntPtr token = IntPtr.Zero;

            // Call the API
            if (LogonUser(userName, domain, password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, ref token)) {
                return new NtUser(userName, domain, token);
            } else {
                return null;
            }
        }

        private void SplitIntoUserNameAndDomain(string userNameAndDomain, out string userName, out string domain) {
            int token = userNameAndDomain.IndexOf('\\');
            if (token > 0) {
                domain = userNameAndDomain.Substring(0, token);
                userName = userNameAndDomain.Substring(token + 1);
            } else {
                domain = null;
                userName = userNameAndDomain;
            }
        }

        /// <summary>
        /// A user that was authenticated using NT auth.
        /// </summary>
        public class NtUser : IUser {
            private readonly string _userName;
            private readonly string _domain;
            private readonly IntPtr _token;

            /// <summary>
            /// constructor.
            /// </summary>
            public NtUser(string userName, string domain, IntPtr token) {
                _userName = userName;
                _domain = domain;
                _token = token;
            }

            /// <summary>
            /// The user name.
            /// </summary>
            public string UserName {
                get { return _userName; }
            }

            /// <summary>
            /// the domain.
            /// </summary>
            public string Domain {
                get { return _domain; }
            }

            /// <summary>
            /// The user token returned by auth system.
            /// </summary>
            public IntPtr Token {
                get { return _token; }
            }
        }
    }
}
